/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "wifi_device.h"

#include <securec.h>
#include <stdio.h>
#include <stdlib.h>

#include "wifi_device_util.h"
#include "wifi_hotspot_config.h"
#include "sys/fdcm.h"

#define WIFI_RECONN_POLICY_ENABLE 1
#define WIFI_RECONN_POLICY_TIMEOUT 0xFFFF
#define WIFI_RECONN_POLICY_PERIOD 100
#define WIFI_RECONN_POLICY_MAX_TRY_COUNT 100
#define WIFI_DISCONNECT_REASON_NO_AP 1
#define WIFI_DEFAULT_KEY_FOR_PSK "wifipskmode"
#define WLAN_STA_NAME "en1"
#define WIFI_FILE "wifi.cfg"
#define WIFI_FILE_EXIST 1
#define WIFI_FILE_UNEXIST 0

int g_wifiStaStatus = WIFI_STA_NOT_ACTIVE;
extern int g_wifiApStatus;
static WifiDeviceConfig g_wifiConfigs[WIFI_MAX_CONFIG_SIZE] = {
	{ { 0 }, { 0 }, { 0 }, 0, WIFI_CONFIG_INVALID, 0, 0 }
};
static WifiEvent *g_wifiEvents[WIFI_MAX_EVENT_SIZE] = { 0 };
static int g_connectState = WIFI_STATE_NOT_AVALIABLE;
static int g_networkId = -1;
static int g_networkConfigReadFlag = 0;
static fdcm_handle_t *fdcm;
/* Flash Distribution */
#define FDCM_FLASH_START_ADDR (1996 * 1024)
#define FLASH_DEVICE_NUM 0
#define FDCM_SIZE (4 * 1024)
#define SIZE_WIFI_CONFIG (sizeof(WifiDeviceConfig) * WIFI_MAX_CONFIG_SIZE)

static WifiErrorCode WriteNetworkConfig(void)
{
	fdcm = fdcm_open(FLASH_DEVICE_NUM, FDCM_FLASH_START_ADDR, FDCM_SIZE);
	if (fdcm == NULL) {
		return ERROR_WIFI_UNKNOWN;
	}
	fdcm_write(fdcm, g_wifiConfigs, SIZE_WIFI_CONFIG);
	fdcm_close(fdcm);
	return WIFI_SUCCESS;
}

static WifiErrorCode ReadNetworkConfig(void)
{
	fdcm = fdcm_open(FLASH_DEVICE_NUM, FDCM_FLASH_START_ADDR, FDCM_SIZE);
	fdcm_read(fdcm, g_wifiConfigs, SIZE_WIFI_CONFIG);
	fdcm_close(fdcm);
	return WIFI_SUCCESS;
}

static void StaSetLocaladdr(const char *netif_name, int gw, int ipaddr,
			    int netmask)
{
	xr_wifi_set_local_ip(netif_name, gw, ipaddr, netmask);
	return;
}

static void StaSetDNSServer(int switcher)
{
	for (int i = 0; i < WIFI_MAX_DNS_NUM; i++) {
		if (switcher == XR_WIFI_EVT_CONNECTED) {
			xr_wifi_set_dns_server(i,
					       g_wifiConfigs[g_networkId]
						       .staticIp.dnsServers[i]);
		} else {
			xr_wifi_set_dns_server(i, 0);
		}
	}
	return;
}

static void StaSetWifiNetConfig(int switcher)
{
	if (switcher == XR_WIFI_EVT_CONNECTED) {
		if (g_wifiConfigs[g_networkId].ipType == DHCP) {
			xr_wifi_dhcp_enable(WLAN_STA_NAME, 1);
		} else if (g_wifiConfigs[g_networkId].ipType == STATIC_IP) {
			StaSetLocaladdr(
				WLAN_STA_NAME,
				g_wifiConfigs[g_networkId].staticIp.gateway,
				g_wifiConfigs[g_networkId].staticIp.ipAddress,
				g_wifiConfigs[g_networkId].staticIp.netmask);
			StaSetDNSServer(XR_WIFI_EVT_CONNECTED);
			xr_wifi_netif_status_set(WLAN_STA_NAME, 1);
		}
	} else if (switcher == XR_WIFI_EVT_DISCONNECTED) {
		if (g_wifiConfigs[g_networkId].ipType == DHCP) {
			xr_wifi_dhcp_enable(WLAN_STA_NAME, 0);
			StaSetLocaladdr(WLAN_STA_NAME, 0, 0, 0);
		} else if (g_wifiConfigs[g_networkId].ipType == STATIC_IP) {
			StaSetLocaladdr(WLAN_STA_NAME, 0, 0, 0);
			StaSetDNSServer(XR_WIFI_EVT_DISCONNECTED);
			xr_wifi_netif_status_set(WLAN_STA_NAME, 0);
		}
	}
	return;
}

static void DispatchScanStateChangeEvent(const xr_wifi_event *xrEvent,
					 const WifiEvent *hosEvent,
					 WifiEventState event)
{
	if (hosEvent->OnWifiScanStateChanged == NULL) {
		return;
	}

	int size = 0;
	if (event == WIFI_STATE_NOT_AVALIABLE) {
		hosEvent->OnWifiScanStateChanged(event, size);
		return;
	}

	if (xrEvent->event == XR_WIFI_EVT_SCAN_DONE) {
		size = xrEvent->info.wifi_scan_done.bss_num;
		hosEvent->OnWifiScanStateChanged(event, size);
	}
}

static void DispatchConnectEvent(const xr_wifi_event *xrEvent,
				 const WifiEvent *hosEvent)
{
	if (hosEvent->OnWifiConnectionChanged == NULL) {
		return;
	}

	int cpyErr;
	WifiLinkedInfo info = { 0 };

	if (xrEvent->event == XR_WIFI_EVT_CONNECTED) {
		g_connectState = WIFI_STATE_AVALIABLE;
		cpyErr = memcpy_s(&info.ssid, WIFI_MAX_SSID_LEN,
				  xrEvent->info.wifi_connected.ssid,
				  XR_WIFI_MAX_SSID_LEN + 1);
		if (cpyErr != EOK) {
			printf("[wifi_service]:DispatchConnectEvent memcpy failed, err = %d\n",
			       cpyErr);
			return;
		}

		cpyErr = memcpy_s(&info.bssid, WIFI_MAC_LEN,
				  xrEvent->info.wifi_connected.bssid,
				  WIFI_MAC_LEN);
		if (cpyErr != EOK) {
			printf("[wifi_service]:DispatchConnectEvent memcpy failed, err = %d\n",
			       cpyErr);
			return;
		}

		// StaSetWifiNetConfig(XR_WIFI_EVT_CONNECTED);
		hosEvent->OnWifiConnectionChanged(WIFI_STATE_AVALIABLE, &info);
		return;
	}

	if (xrEvent->event == XR_WIFI_EVT_STA_FCON_NO_NETWORK &&
	    g_connectState == WIFI_STATE_AVALIABLE) {
		return;
	}

	info.disconnectedReason = WIFI_DISCONNECT_REASON_NO_AP;

	if (xrEvent->event == XR_WIFI_EVT_DISCONNECTED) {
		cpyErr = memcpy_s(&info.bssid, WIFI_MAC_LEN,
				  xrEvent->info.wifi_disconnected.bssid,
				  WIFI_MAC_LEN);
		if (cpyErr != EOK) {
			printf("[wifi_service]:DispatchConnectEvent memcpy failed, err = %d\n",
			       cpyErr);
			return;
		}
		info.disconnectedReason =
			xrEvent->info.wifi_disconnected.reason_code;
	}

	// StaSetWifiNetConfig(XR_WIFI_EVT_DISCONNECTED);
	hosEvent->OnWifiConnectionChanged(WIFI_STATE_NOT_AVALIABLE, &info);
}

static void DispatchStaConnectEvent(const xr_wifi_event *xrEvent,
				    const WifiEvent *hosEvent)
{
	int cpyErr;
	StationInfo info = { 0 };
	if (xrEvent->event == XR_WIFI_EVT_STA_CONNECTED) {
		if (hosEvent->OnHotspotStaJoin == NULL) {
			return;
		}

		cpyErr = memcpy_s(&info.macAddress, WIFI_MAC_LEN,
				  xrEvent->info.ap_sta_connected.addr,
				  WIFI_MAC_LEN);
		if (cpyErr != EOK) {
			printf("[wifi_service]:DispatchStaConnectEvent memcpy failed, err = %d\n",
			       cpyErr);
			return;
		}

		hosEvent->OnHotspotStaJoin(&info);
		return;
	}

	if (hosEvent->OnHotspotStaLeave == NULL) {
		return;
	}

	cpyErr = memcpy_s(&info.macAddress, WIFI_MAC_LEN,
			  xrEvent->info.ap_sta_disconnected.addr, WIFI_MAC_LEN);
	if (cpyErr != EOK) {
		printf("[wifi_service]:DispatchStaConnectEvent memcpy failed, err = %d\n",
		       cpyErr);
		return;
	}
	info.disconnectedReason = xrEvent->info.ap_sta_disconnected.reason_code;
	hosEvent->OnHotspotStaLeave(&info);
}

static void DispatchApStartEvent(const WifiEvent *hosEvent)
{
	if (hosEvent->OnHotspotStateChanged == NULL) {
		return;
	}

	hosEvent->OnHotspotStateChanged(WIFI_STATE_AVALIABLE);
}

static void DispatchEvent(const xr_wifi_event *xrEvent,
			  const WifiEvent *hosEvent)
{
	switch (xrEvent->event) {
	case XR_WIFI_EVT_SCAN_DONE:
		DispatchScanStateChangeEvent(xrEvent, hosEvent,
					     WIFI_STATE_AVALIABLE);
		break;
	case XR_WIFI_EVT_CONNECTED:
	case XR_WIFI_EVT_DISCONNECTED:
	case XR_WIFI_EVT_STA_FCON_NO_NETWORK:
		DispatchConnectEvent(xrEvent, hosEvent);
		break;
	case XR_WIFI_EVT_STA_CONNECTED:
	case XR_WIFI_EVT_STA_DISCONNECTED:
		DispatchStaConnectEvent(xrEvent, hosEvent);
		break;
	case XR_WIFI_EVT_AP_START:
		DispatchApStartEvent(hosEvent);
		break;
	default:
		/* event not supported in current version, do nothing */
		break;
	}
}

static void XrWifiWpaEventCb(const xr_wifi_event *xrEvent)
{
	if (xrEvent == NULL) {
		return;
	}
	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return;
	}
	for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
		if (g_wifiEvents[i] == NULL) {
			continue;
		}
		DispatchEvent(xrEvent, g_wifiEvents[i]);
	}
	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return;
	}
}

static void RegisterXrCallback(void)
{
	int Ret = xr_wifi_register_event_callback(XrWifiWpaEventCb);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:RegisterXrCallback register callback failed\n");
	}
	Ret = xr_wifi_config_callback(1, 0, 0);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:ConfigXrCallback failed\n");
	}
}

static void UnRegisterXrCallback(void)
{
	int Ret = xr_wifi_register_event_callback(NULL);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:UnRegisterXrCallback register callback failed\n");
	}
	Ret = xr_wifi_config_callback(0, 0, 0);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:ConfigXrCallback failed\n");
	}
}

WifiErrorCode EnableWifi(void)
{
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (g_wifiStaStatus == WIFI_STA_ACTIVE) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_BUSY;
	}

	char ifName[WIFI_IFNAME_MAX_SIZE + 1] = { 0 };
	int len = sizeof(ifName);
	int Ret;

	Ret = xr_wifi_sta_start(ifName, &len);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:EnableWifi sta start fail\n");
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_STARTED;
	}

	// Ret = xr_wifi_sta_set_reconnect_policy(WIFI_RECONN_POLICY_ENABLE, WIFI_RECONN_POLICY_TIMEOUT,
	//     WIFI_RECONN_POLICY_PERIOD, WIFI_RECONN_POLICY_MAX_TRY_COUNT);
	// if (Ret != XR_WIFI_OK) {
	//     printf("[wifi_service]:EnableWifi set reconn policy fail\n");
	//     if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
	//         return ERROR_WIFI_UNKNOWN;
	//     }
	//     return ERROR_WIFI_UNKNOWN;
	// }

	g_wifiStaStatus = WIFI_STA_ACTIVE;

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

WifiErrorCode DisableWifi(void)
{
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_STARTED;
	}

	int Ret;

	Ret = xr_wifi_sta_stop();
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:DisableWifi failed to stop sta\n");
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_STARTED;
	}

	g_wifiStaStatus = WIFI_STA_NOT_ACTIVE;
	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

int IsWifiActive(void)
{
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	int ret = g_wifiStaStatus;

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	return ret;
}

WifiErrorCode Scan(void)
{
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_STARTED;
	}
	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
		if (g_wifiEvents[i] == NULL) {
			continue;
		}
		DispatchScanStateChangeEvent(NULL, g_wifiEvents[i],
					     WIFI_STATE_NOT_AVALIABLE);
	}
	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	int Ret;

	Ret = xr_wifi_sta_scan();
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:Scan failed to start sta scan\n");
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

static xr_wifi_scan_type ScanTypeSwitch(WifiScanType type)
{
	xr_wifi_scan_type ret = XR_WIFI_BASIC_SCAN;

	switch (type) {
	case WIFI_FREQ_SCAN:
		ret = XR_WIFI_CHANNEL_SCAN;
		break;
	case WIFI_SSID_SCAN:
		ret = XR_WIFI_SSID_SCAN;
		break;
	case WIFI_BSSID_SCAN:
		ret = XR_WIFI_BSSID_SCAN;
		break;
	case WIFI_BAND_SCAN:
		ret = XR_WIFI_BASIC_SCAN;
		break;
	default:
		break;
	}

	return ret;
}

WifiErrorCode AdvanceScan(WifiScanParams *params)
{
	if (params == NULL) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_STARTED;
	}

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
		if (g_wifiEvents[i] == NULL) {
			continue;
		}
		DispatchScanStateChangeEvent(NULL, g_wifiEvents[i],
					     WIFI_STATE_NOT_AVALIABLE);
	}
	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	int Ret;
	int cpyErr;
	xr_wifi_scan_params sp = { 0 };

	cpyErr = memcpy_s(sp.ssid, sizeof(sp.ssid), params->ssid,
			  params->ssidLen);
	if (cpyErr != EOK) {
		return ERROR_WIFI_UNKNOWN;
	}
	cpyErr = memcpy_s(sp.bssid, sizeof(sp.bssid), params->bssid,
			  sizeof(params->bssid));
	if (cpyErr != EOK) {
		return ERROR_WIFI_UNKNOWN;
	}
	sp.ssid_len = params->ssidLen;
	sp.scan_type = ScanTypeSwitch(params->scanType);
	sp.channel = FrequencyToChannel(params->freqs);

	Ret = xr_wifi_sta_advance_scan(&sp);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:Advance Scan failed\n");
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

WifiErrorCode GetScanInfoList(WifiScanInfo *result, unsigned int *size)
{
	if (result == NULL || size == NULL || *size == 0) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	unsigned int num = WIFI_SCAN_HOTSPOT_LIMIT;

	xr_wifi_ap_info *pstResults =
		malloc(sizeof(xr_wifi_ap_info) * WIFI_SCAN_HOTSPOT_LIMIT);
	if (pstResults == NULL) {
		printf("[wifi_error]:not enough memory\n");
		return ERROR_WIFI_UNKNOWN;
	}

	int Ret = xr_wifi_sta_scan_results(pstResults, &num);
	if (Ret != XR_WIFI_OK) {
		printf("[wifi_service]:GetScanInfoList xr_wifi_sta_scan_results fail\n");
		free(pstResults);
		return ERROR_WIFI_UNKNOWN;
	}

	if (*size < num) {
		num = *size;
	}

	int cpyErr;
	for (unsigned int i = 0; i < num; i++) {
		cpyErr = memcpy_s(result[i].ssid, WIFI_MAX_SSID_LEN,
				  pstResults[i].ssid, XR_WIFI_MAX_SSID_LEN + 1);
		if (cpyErr != EOK) {
			free(pstResults);
			printf("[wifi_service]:GetScanInfoList memcpy failed, err = %d\n",
			       cpyErr);
			return ERROR_WIFI_UNKNOWN;
		}

		cpyErr = memcpy_s(result[i].bssid, WIFI_MAC_LEN,
				  pstResults[i].bssid, WIFI_MAC_LEN);
		if (cpyErr != EOK) {
			free(pstResults);
			printf("[wifi_service]:GetScanInfoList memcpy failed, err = %d\n",
			       cpyErr);
			return ERROR_WIFI_UNKNOWN;
		}

		result[i].securityType = HiSecToHoSec(pstResults[i].auth);
		result[i].rssi = pstResults[i].rssi;
		result[i].frequency = ChannelToFrequency(pstResults[i].channel);
	}

	free(pstResults);
	*size = num;

	return WIFI_SUCCESS;
}

WifiErrorCode AddDeviceConfig(const WifiDeviceConfig *config, int *result)
{
	if (config == NULL || result == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	int netId = WIFI_CONFIG_INVALID;
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	// for (int i = 0; i < WIFI_MAX_CONFIG_SIZE; i++) {
	// 	if (strcmp(g_wifiConfigs[i].ssid, config->ssid) == 0) {
	// 		printf("SSID exist,no need add\n");
	// 		*result = i;
	// 		return WIFI_SUCCESS;
	// 	}
	// }

	for (int i = 0; i < WIFI_MAX_CONFIG_SIZE; i++) {
		if (g_wifiConfigs[i].netId != i) {
			netId = i;
			break;
		}
	}

	if (netId == WIFI_CONFIG_INVALID) {
		printf("[wifi_service]:AddDeviceConfig wifi config is full, delete one first\n");
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_BUSY;
	}

	int cpyErr = memcpy_s(&g_wifiConfigs[netId], sizeof(WifiDeviceConfig),
			      config, sizeof(WifiDeviceConfig));
	if (cpyErr != EOK) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		printf("[wifi_service]:AddDeviceConfig memcpy failed, err = %d\n",
		       cpyErr);
		return ERROR_WIFI_UNKNOWN;
	}

	g_wifiConfigs[netId].netId = netId;
	if (WriteNetworkConfig() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	*result = netId;
	return WIFI_SUCCESS;
}

WifiErrorCode GetDeviceConfigs(WifiDeviceConfig *result, unsigned int *size)
{
	if (result == NULL || size == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	unsigned int retIndex = 0;

	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (g_networkConfigReadFlag == 0) {
		g_networkConfigReadFlag = 1;
		ReadNetworkConfig();
	}

	for (int i = 0; i < WIFI_MAX_CONFIG_SIZE; i++) {
		if (g_wifiConfigs[i].netId != i) {
			continue;
		}

		int cpyErr =
			memcpy_s(&result[retIndex], sizeof(WifiDeviceConfig),
				 &g_wifiConfigs[i], sizeof(WifiDeviceConfig));
		if (cpyErr != EOK) {
			if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
				return ERROR_WIFI_UNKNOWN;
			}
			printf("[wifi_service]:GetDeviceConfig memcpy failed, err = %d\n",
			       cpyErr);
			return ERROR_WIFI_UNKNOWN;
		}

		retIndex++;
	}

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (retIndex == 0) {
		return ERROR_WIFI_NOT_AVAILABLE;
	}

	*size = retIndex;
	return WIFI_SUCCESS;
}

static WifiErrorCode StaConnect(unsigned int chan,
				xr_wifi_assoc_request *assocReq, int pskType)
{
	int Ret = 0;
	int lastState = g_connectState;

	g_connectState = WIFI_STATE_NOT_AVALIABLE;
	if (chan == 0) {
		Ret = xr_wifi_sta_connect(assocReq);
	} else {
		xr_wifi_fast_assoc_request fastReq = { 0 };
		fastReq.channel = chan;
		Ret += memcpy_s(&fastReq.req, sizeof(xr_wifi_assoc_request),
				assocReq, sizeof(xr_wifi_assoc_request));
		if (pskType == WIFI_PSK_TYPE_HEX) {
			Ret += memcpy_s(fastReq.req.key,
					sizeof(fastReq.req.key),
					WIFI_DEFAULT_KEY_FOR_PSK,
					sizeof(WIFI_DEFAULT_KEY_FOR_PSK));
			Ret += memcpy_s(fastReq.psk, sizeof(fastReq.psk),
					assocReq->key, XR_WIFI_STA_PSK_LEN);
			fastReq.psk_flag = XR_WIFI_WPA_PSK_USE_OUTER;
		}
		if (Ret != EOK) {
			printf("[wifi_service]:StaConnect memcpy failed, err = %d\n",
			       Ret);
			g_connectState = lastState;
			return ERROR_WIFI_UNKNOWN;
		}
		Ret = xr_wifi_sta_fast_connect(&fastReq);
		if (memset_s(&fastReq, sizeof(xr_wifi_fast_assoc_request), 0,
			     sizeof(xr_wifi_fast_assoc_request)) != EOK) {
			printf("[wifi_service]:StaConnect memset failed\n");
		}
	}
	if (memset_s(assocReq, sizeof(xr_wifi_assoc_request), 0,
		     sizeof(xr_wifi_assoc_request)) != EOK) {
		printf("[wifi_service]:StaConnect memset failed\n");
	}
	if (Ret != XR_WIFI_OK) {
		g_connectState = lastState;
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

WifiErrorCode ConnectTo(int networkId)
{
	if (networkId >= WIFI_MAX_CONFIG_SIZE || networkId < 0) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	if (g_wifiStaStatus == WIFI_STA_ACTIVE) {
		if (LockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
	} else {
		return ERROR_WIFI_NOT_STARTED;
	}

	if (g_wifiConfigs[networkId].netId != networkId) {
		if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_NOT_AVAILABLE;
	}

	g_networkId = networkId;
	xr_wifi_assoc_request assocReq = { 0 };
	assocReq.auth = HoSecToHiSec(g_wifiConfigs[networkId].securityType);

	int cpyErr = memcpy_s(assocReq.ssid, sizeof(assocReq.ssid),
			      g_wifiConfigs[networkId].ssid,
			      sizeof(g_wifiConfigs[networkId].ssid));
	cpyErr += memcpy_s(assocReq.key, sizeof(assocReq.key),
			   g_wifiConfigs[networkId].preSharedKey,
			   sizeof(g_wifiConfigs[networkId].preSharedKey));
	cpyErr += memcpy_s(assocReq.bssid, sizeof(assocReq.bssid),
			   g_wifiConfigs[networkId].bssid,
			   sizeof(g_wifiConfigs[networkId].bssid));
	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (cpyErr != EOK) {
		printf("[wifi_service]:ConnectTo memcpy failed, err = %d\n",
		       cpyErr);
		return ERROR_WIFI_UNKNOWN;
	}

	unsigned int chan = FrequencyToChannel(g_wifiConfigs[networkId].freq);
	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (StaConnect(chan, &assocReq, g_wifiConfigs[networkId].wapiPskType) !=
	    WIFI_SUCCESS) {
		if (UnlockWifiEventLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_UNKNOWN;
	}
	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	return WIFI_SUCCESS;
}

WifiErrorCode Disconnect(void)
{
	if (g_wifiStaStatus != WIFI_STA_ACTIVE) {
		return ERROR_WIFI_NOT_STARTED;
	}
	int Ret = xr_wifi_sta_disconnect();
	if (Ret != XR_WIFI_OK) {
		return ERROR_WIFI_UNKNOWN;
	}
	return WIFI_SUCCESS;
}

WifiErrorCode RemoveDevice(int networkId)
{
	if (networkId >= WIFI_MAX_CONFIG_SIZE || networkId < 0) {
		return ERROR_WIFI_INVALID_ARGS;
	}
	if (LockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	if (memset_s(&g_wifiConfigs[networkId], sizeof(WifiDeviceConfig), 0,
		     sizeof(WifiDeviceConfig)) != EOK) {
		printf("[wifi_service]:removeDevice memset failed\n");
	}
	g_wifiConfigs[networkId].netId = WIFI_CONFIG_INVALID;

	if (WriteNetworkConfig() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	return WIFI_SUCCESS;
}

static int GetLocalWifiIp(int *const ip)
{
	return xr_wifi_get_local_ip(WLAN_STA_NAME, ip);
}

WifiErrorCode GetLinkedInfo(WifiLinkedInfo *result)
{
	if (result == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	xr_wifi_status connectStatus = { 0 };
	int Ret = xr_wifi_sta_get_connect_info(&connectStatus);
	if (Ret != XR_WIFI_OK) {
		return ERROR_WIFI_UNKNOWN;
	}

	int cpyErr = memcpy_s(result->ssid, WIFI_MAX_SSID_LEN,
			      connectStatus.ssid, XR_WIFI_MAX_SSID_LEN + 1);
	if (cpyErr != EOK) {
		printf("[wifi_service]:GetLinkedInfo memcpy failed, err = %d\n",
		       cpyErr);
		return ERROR_WIFI_UNKNOWN;
	}

	cpyErr = memcpy_s(result->bssid, WIFI_MAC_LEN, connectStatus.bssid,
			  WIFI_MAC_LEN);
	if (cpyErr != EOK) {
		printf("[wifi_service]:GetLinkedInfo memcpy failed, err = %d\n",
		       cpyErr);
		return ERROR_WIFI_UNKNOWN;
	}

	if (connectStatus.status == XR_WIFI_CONNECTED) {
		result->connState = WIFI_CONNECTED;
		result->rssi = xr_wifi_sta_get_ap_rssi();
	} else {
		result->connState = WIFI_DISCONNECTED;
	}

	if (GetLocalWifiIp(&(result->ipAddress)) != EOK) {
		return ERROR_WIFI_UNKNOWN;
	}

	return WIFI_SUCCESS;
}

WifiErrorCode RegisterWifiEvent(WifiEvent *event)
{
	if (event == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	int emptySlot = WIFI_CONFIG_INVALID;

	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
		if (g_wifiEvents[i] == event) {
			if (UnlockWifiEventLock() != WIFI_SUCCESS) {
				return ERROR_WIFI_UNKNOWN;
			}
			return ERROR_WIFI_INVALID_ARGS;
		}

		if (g_wifiEvents[i] != NULL) {
			continue;
		}

		emptySlot = i;
		break;
	}

	if (emptySlot == WIFI_CONFIG_INVALID) {
		if (UnlockWifiEventLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return ERROR_WIFI_BUSY;
	}

	g_wifiEvents[emptySlot] = event;
	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	RegisterXrCallback();

	return WIFI_SUCCESS;
}

WifiErrorCode UnRegisterWifiEvent(const WifiEvent *event)
{
	if (event == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	if (LockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}

	for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
		if (g_wifiEvents[i] != event) {
			continue;
		}

		g_wifiEvents[i] = 0;

		if (UnlockWifiEventLock() != WIFI_SUCCESS) {
			return ERROR_WIFI_UNKNOWN;
		}
		return WIFI_SUCCESS;
	}

	if (UnlockWifiEventLock() != WIFI_SUCCESS) {
		return ERROR_WIFI_UNKNOWN;
	}
	return ERROR_WIFI_UNKNOWN;
}

WifiErrorCode GetDeviceMacAddress(unsigned char *result)
{
	if (result == NULL) {
		return ERROR_WIFI_INVALID_ARGS;
	}

	int Ret = xr_wifi_get_macaddr((char *)result, WIFI_MAC_LEN);
	if (Ret != XR_WIFI_OK) {
		return ERROR_WIFI_UNKNOWN;
	}
	return WIFI_SUCCESS;
}
